package me.zhengjie.modules.security.service;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.modules.security.config.WxConfig;
import me.zhengjie.modules.security.domain.WxLoginUser;
import me.zhengjie.modules.security.service.dto.JwtUserDto;
import me.zhengjie.modules.system.domain.User;
import me.zhengjie.modules.system.mapper.UserMapper;
import me.zhengjie.modules.system.service.UserService;
import me.zhengjie.utils.RedisUtils;
import me.zhengjie.utils.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 微信登录服务
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WxLoginService {

    private final WxConfig wxConfig;
    private final RestTemplate restTemplate;
    private final UserMapper userMapper;
    private final UserService userService;
    private final RedisUtils redisUtils;
    private final OnlineUserService onlineUserService;
    private final TokenProvider tokenProvider;

    /**
     * 获取微信授权URL
     */
    public String getWxAuthUrl() {
        String state = UUID.randomUUID().toString();
        // 将state存入Redis，用于回调验证，设置5分钟过期
        String redisKey = "wx_state:" + state;
        redisUtils.set(redisKey, state, 300);
        log.info("Generated state: {}, saved to Redis key: {}", state, redisKey);
        return wxConfig.getAuthCodeUrl(state);
    }

    /**
     * 微信登录回调处理
     */
    public Map<String, Object> wxCallback(String code, String state) {
        log.info("wxCallback called with code: {}, state: {}", code, state);
        Map<String, Object> result = new HashMap<>();

        try {
            // 检查是否是小程序登录
            boolean isMiniProgram = state == null || state.isEmpty() || "undefined".equals(state);
            log.info("Is mini program login: {}", isMiniProgram);

            // 小程序登录流程
            try {
                return handleMiniProgramLogin(code);
            } catch (Exception e) {
                log.error("小程序登录失败，尝试网页授权登录: {}", e.getMessage());
                // 如果小程序登录失败，尝试网页授权登录
                return handleWebLogin(code, state);
            }
        } catch (Exception e) {
            log.error("微信登录处理异常", e);
            result.put("success", false);
            result.put("message", "微信登录处理异常: " + e.getMessage());
            return result;
        }
    }

    /**
     * 处理小程序登录
     */
    private Map<String, Object> handleMiniProgramLogin(String code) {
        log.info("Handling mini program login with code: {}", code);
        Map<String, Object> result = new HashMap<>();

        try {
            // 获取小程序会话信息
            String jscode2SessionUrl = wxConfig.getJscode2SessionUrl(code);
            log.info("Requesting jscode2session from URL: {}", jscode2SessionUrl);

            ResponseEntity<String> sessionResponse = restTemplate.exchange(
                    jscode2SessionUrl, HttpMethod.GET, null, String.class);

            log.info("Jscode2session response: {}", sessionResponse.getBody());

            JSONObject sessionJson = JSON.parseObject(sessionResponse.getBody());

            if (sessionJson.containsKey("errcode") && sessionJson.getIntValue("errcode") != 0) {
                String errcode = sessionJson.getString("errcode");
                String errmsg = sessionJson.getString("errmsg");
                log.error("Failed to get session. Error code: {}, message: {}", errcode, errmsg);
                result.put("success", false);
                result.put("message", "获取微信会话失败: " + errmsg);
                return result;
            }

            String openId = sessionJson.getString("openid");
            String sessionKey = sessionJson.getString("session_key");

            log.info("Mini program login successful. OpenID: {}", openId);

            // 查找或创建用户
            User user = userMapper.findByOpenid(openId);

            if (user == null) {
                // 创建新用户
                user = new User();
                user.setUsername("wx_" + openId);
                user.setNickName("微信用户");
                user.setOpenid(openId);
                user.setEnabled(true);
                userService.create(user);
                log.info("Created new user for mini program login: {}", user.getUsername());
            } else {
                log.info("Found existing user for mini program login: {}", user.getUsername());
            }

            // 生成token
            JwtUserDto jwtUserDto = (JwtUserDto) userService.loadUserByUsername(user.getUsername());
            String token = tokenProvider.createToken(jwtUserDto);

            // 保存在线用户
            onlineUserService.save(jwtUserDto, token, null);

            // 返回登录成功信息
            result.put("success", true);
            result.put("token", token);
            result.put("user", user);

            log.info("Mini program login completed successfully for user: {}", user.getUsername());
            return result;
        } catch (Exception e) {
            log.error("小程序登录处理异常", e);
            result.put("success", false);
            result.put("message", "小程序登录处理异常: " + e.getMessage());
            return result;
        }
    }

    /**
     * 处理网页授权登录
     */
    private Map<String, Object> handleWebLogin(String code, String state) {
        log.info("Handling web login with code: {}, state: {}", code, state);
        Map<String, Object> result = new HashMap<>();

        // 验证state
        String redisKey = "wx_state:" + state;
        String savedState = (String) redisUtils.get(redisKey);
        log.info("Validating state - Provided: {}, Saved in Redis: {}, Redis Key: {}",
                state, savedState, redisKey);

        // 临时解决方案：如果Redis中没有state，但是有code，我们仍然继续处理
        boolean stateValid = StrUtil.isNotBlank(state) &&
                (StrUtil.isNotBlank(savedState) && savedState.equals(state));

        if (!stateValid) {
            log.warn("State validation failed, but continuing with code: {}", code);
            // 继续处理，不返回错误
        } else {
            // 清除Redis中的state
            redisUtils.del(redisKey);
            log.info("State validated successfully, removed from Redis");
        }

        // 获取微信访问令牌
        String accessTokenUrl = wxConfig.getAccessTokenUrl(code);
        log.info("Requesting access token from URL: {}", accessTokenUrl);

        ResponseEntity<String> accessTokenResponse = restTemplate.exchange(
                accessTokenUrl, HttpMethod.GET, null, String.class);

        log.info("Access token response: {}", accessTokenResponse.getBody());

        JSONObject accessTokenJson = JSON.parseObject(accessTokenResponse.getBody());

        if (accessTokenJson.containsKey("errcode")) {
            String errcode = accessTokenJson.getString("errcode");
            String errmsg = accessTokenJson.getString("errmsg");
            log.error("Failed to get access token. Error code: {}, message: {}", errcode, errmsg);
            result.put("success", false);
            result.put("message", "获取微信访问令牌失败: " + errmsg);
            return result;
        }

        String accessToken = accessTokenJson.getString("access_token");
        String openId = accessTokenJson.getString("openid");

        // 获取微信用户信息
        String userInfoUrl = wxConfig.getUserInfoUrl(accessToken, openId);
        ResponseEntity<String> userInfoResponse = restTemplate.exchange(
                userInfoUrl, HttpMethod.GET, null, String.class);

        JSONObject userInfoJson = JSON.parseObject(userInfoResponse.getBody());

        if (userInfoJson.containsKey("errcode")) {
            result.put("success", false);
            result.put("message", "获取微信用户信息失败: " + userInfoJson.getString("errmsg"));
            return result;
        }

        // 转换为WxLoginUser对象
        WxLoginUser wxLoginUser = JSON.parseObject(userInfoResponse.getBody(), WxLoginUser.class);

        // 查找或创建用户
        User user = userMapper.findByOpenid(wxLoginUser.getOpenid());

        if (user == null) {
            // 创建新用户
            user = new User();
            user.setUsername("wx_" + wxLoginUser.getOpenid());
            user.setNickName(wxLoginUser.getNickname());
            user.setAvatar(wxLoginUser.getHeadimgurl());
            user.setOpenid(wxLoginUser.getOpenid());
            user.setEnabled(true);
            userService.create(user);
            log.info("Created new user with openid: {}", wxLoginUser.getOpenid());
        } else {
            log.info("Found existing user with openid: {}", wxLoginUser.getOpenid());
        }

        // 生成token
        JwtUserDto jwtUserDto = (JwtUserDto) userService.loadUserByUsername(user.getUsername());
        String token = tokenProvider.createToken(jwtUserDto);

        // 保存在线用户
        onlineUserService.save(jwtUserDto, token, null);

        // 返回登录成功信息
        result.put("success", true);
        result.put("token", token);
        result.put("user", user);

        return result;
    }
} 